package com.ctw.tinyservices.id.sdk.util;

import com.ctw.tinyservices.id.common.utils.LogUtils;
import com.ctw.tinyservices.id.sdk.config.IdSdkConfig;
import okhttp3.*;
import okhttp3.internal.Util;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author TongWei.Chen 2022/03/08 12:16
 *
 * Http工具类
 **/
public final class OkHttpUtils {

    private OkHttpUtils() {}

    public static String get(String url, Map<String,String> paramMap, Map<String,String> headers) {
        return get(url, paramMap, headers, IdSdkConfig.getInstance().getReadTimeout(), IdSdkConfig.getInstance().getConnectTimeout());
    }

    public static String get(String url, Map<String,String> paramMap, Map<String,String> headers, int readTimeout, int connectTimeout) {
        if (null != paramMap && paramMap.size() > 0) {
            String param = toHttpParam(paramMap);
            StringBuilder urlBuilder = new StringBuilder();
            if (url.endsWith("?")) {
                url = urlBuilder.append(url).append(param).toString();
            } else {
                url = urlBuilder.append(url).append("?").append(param).toString();
            }
        }
        LogUtils.info(OkHttpUtils.class, "get request ready start, url is [{}], headers is [{}]", url, headers);
        Request.Builder requestBuilder = new Request.Builder().url(url).get()
                .cacheControl(CacheControl.FORCE_NETWORK);
        String result = queryString(headers, requestBuilder, readTimeout, connectTimeout);
        LogUtils.info(OkHttpUtils.class, "get request has finished, url is [{}], headers is [{}], result is [{}]", url, headers, result);
        return result;
    }

    public static String post(String url, Map<String,String> params, Map<String,String> headers) {
        return post(url, params, headers, IdSdkConfig.getInstance().getReadTimeout(), IdSdkConfig.getInstance().getConnectTimeout());
    }

    public static String post(String url, Map<String,String> params, Map<String,String> headers, int readTimeout, int connectTimeout) {
        LogUtils.info(OkHttpUtils.class, "post request ready start, url is [{}], params is [{}], headers is [{}]", url, params, headers);
        FormBody.Builder builder = new FormBody.Builder();
        if (params != null){
            for (Map.Entry<String,String> entry : params.entrySet()){
                builder.add(entry.getKey(),entry.getValue());
            }
        }
        FormBody formBody = builder.build();
        Request.Builder requestBuilder = new Request.Builder().url(url).post(formBody)
                .cacheControl(CacheControl.FORCE_NETWORK);
        String result = queryString(headers, requestBuilder, readTimeout, connectTimeout);
        LogUtils.info(OkHttpUtils.class, "post request has finished, url is [{}], params is [{}], headers is [{}], result is [{}]", url, params, headers, result);
        return result;
    }

    private static String queryString(Map<String, String> headers, Request.Builder requestBuilder, int readTimeout, int connectTimeout) {
        Response response = null;
        try {
            response = callNetwork(headers, requestBuilder, readTimeout, connectTimeout);
            int statusCode = response.code();
            if (statusCode == 200) {
                ResponseBody responseBody = response.body();
                return responseBody != null ? responseBody.string() : "";
            }
            if (statusCode == 304 || statusCode == 504) {
                return null;
            }
            if (! response.isSuccessful()) {
                LogUtils.error(OkHttpUtils.class, "http call fail,code = {}", statusCode);
                return null;
            }
        } catch (Exception e) {
            LogUtils.error(OkHttpUtils.class, e.getMessage(), e);
        } finally {
            Util.closeQuietly(response);
        }
        return null;
    }

    private static Response callNetwork(Map<String, String> headers, Request.Builder requestBuilder, int readTimeout, int connectTimeout) {
        int tryCount = 0;
        if (headers != null && !headers.isEmpty()) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                requestBuilder.header(entry.getKey(), entry.getValue());
            }
        }
        Request request = requestBuilder.build();
        Response response = null;
        while (tryCount < 3) {
            try {
                response = new OkHttpClient().newBuilder()
                        .readTimeout(readTimeout, TimeUnit.SECONDS)
                        .connectTimeout(connectTimeout, TimeUnit.SECONDS)
                        .build()
                        .newCall(request).execute();
                break;
            } catch (IOException e) {
                tryCount ++;
                LogUtils.error(OkHttpUtils.class, "request:{},请求重试次数:{}",request,tryCount, e);
            }
        }
        return response;
    }

    /**
     * Map转a=1&b=2....
     * @param map
     * @return
     */
    private static String toHttpParam(Map<String, String> map) {
        if (map == null || map.isEmpty()) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        String tmp = sb.toString();
        return tmp.substring(0, tmp.length()-1);
    }
}